//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_dataview_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/dataview_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/user_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/notices/notices_dataview"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_dataview_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectDataViewApiImpl) CreateView(ctx context.Context, req *project_dataview_api.CreateViewRequest) (*project_dataview_api.CreateViewResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_dataview_api.CreateViewResponse{
			Code:   project_dataview_api.CreateViewResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_dataview_api.CreateViewResponse{
			Code:   project_dataview_api.CreateViewResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_dataview_api.CreateViewResponse{
			Code:   project_dataview_api.CreateViewResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_dataview_api.CreateViewResponse{
			Code:   project_dataview_api.CreateViewResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	viewId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = dataview_dao.ViewDao.Insert(sessCtx, &dataview_dao.ViewInfoDbItem{
			ViewId:                viewId,
			ProjectId:             req.ProjectId,
			Title:                 req.Title,
			BgColor:               req.BgColor,
			Desc:                  req.Desc,
			OwnerUserId:           sessionItem.UserId,
			CreateTime:            nowTime,
			ExtraUpdateUserIdList: []string{},
		})
		if err != nil {
			return nil, err
		}
		return &project_dataview_api.CreateViewResponse{
			Code:   project_dataview_api.CreateViewResponse_CODE_OK,
			ViewId: viewId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_dataview.CreateViewNotice{
		ProjectId: req.ProjectId,
		ViewId:    viewId,
	})
	return ret.(*project_dataview_api.CreateViewResponse), nil
}

func (apiImpl *ProjectDataViewApiImpl) ListView(ctx context.Context, req *project_dataview_api.ListViewRequest) (*project_dataview_api.ListViewResponse, error) {
	emptyList := []*project_dataview_api.ViewInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_dataview_api.ListViewResponse{
			Code:     project_dataview_api.ListViewResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			ViewList: emptyList,
		}, nil
	}
	//检查项目匹配
	memberItemList, err := project_dao.MemberInfoDao.ListMyProject(ctx, sessionItem.UserId)
	if err != nil {
		return nil, err
	}
	memberRoleMap := map[string]string{}
	projectIdList := []string{}
	match := false
	roleIdList := []string{}
	for _, memberItem := range memberItemList {
		memberRoleMap[memberItem.ProjectId] = memberItem.RoleId
		roleIdList = append(roleIdList, memberItem.RoleId)
		projectIdList = append(projectIdList, memberItem.ProjectId)
		if req.FilterByProjectId && req.ProjectId == memberItem.ProjectId {
			match = true
		}
	}
	if req.FilterByProjectId {
		if !match {
			return &project_dataview_api.ListViewResponse{
				Code:     project_dataview_api.ListViewResponse_CODE_NO_PERMISSION,
				ErrMsg:   "没有权限",
				ViewList: emptyList,
			}, nil
		}
		projectIdList = []string{req.ProjectId}
	}
	//列出view
	count, err := dataview_dao.ViewDao.Count(ctx, projectIdList)
	if err != nil {
		return nil, err
	}
	viewItemList, err := dataview_dao.ViewDao.List(ctx, projectIdList, int64(req.Offset), int64(req.Limit))
	if err != nil {
		return nil, err
	}
	//获取用户信息
	userIdList := []string{}
	for _, viewItem := range viewItemList {
		userIdList = append(userIdList, viewItem.OwnerUserId)
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	roleItemList, err := project_dao.MemberRoleDao.ListById(ctx, projectIdList, roleIdList)
	if err != nil {
		return nil, err
	}
	roleItemMap := map[string]*project_dao.RoleInfoDbItem{}
	for _, roleItem := range roleItemList {
		roleItemMap[roleItem.RoleId] = roleItem
	}

	//获取项目信息
	projectItemList, err := project_dao.ProjectInfoDao.ListById(ctx, projectIdList, false, false)
	if err != nil {
		return nil, err
	}
	projectItemMap := map[string]*project_dao.ProjectInfoDbItem{}
	for _, projectItem := range projectItemList {
		projectItemMap[projectItem.ProjectId] = projectItem
	}
	//生成结果
	viewList := []*project_dataview_api.ViewInfo{}
	for _, viewItem := range viewItemList {
		view := viewItem.ToViewInfo()
		userItem, ok := userItemMap[viewItem.OwnerUserId]
		if ok {
			view.OwnerDisplayName = userItem.BasicInfo.DisplayName
			view.OwnerLogoUri = userItem.BasicInfo.LogoUri
		}
		projectItem, ok := projectItemMap[viewItem.ProjectId]
		view.UserPerm = &project_dataview_api.UserPerm{
			CanUpdate:     sessionItem.UserId == viewItem.OwnerUserId,
			CanRemove:     sessionItem.UserId == viewItem.OwnerUserId,
			CanUpdatePerm: sessionItem.UserId == viewItem.OwnerUserId,
		}
		if ok {
			view.ProjectName = projectItem.BasicInfo.ProjectName
			if projectItem.OwnerUserId == sessionItem.UserId {
				view.UserPerm.CanUpdate = true
				view.UserPerm.CanRemove = true
			}
		}
		roleId, ok := memberRoleMap[viewItem.ProjectId]
		if ok {
			roleItem, ok := roleItemMap[roleId]
			if ok {
				if roleItem.BasicInfo.Admin {
					view.UserPerm.CanUpdate = true
					view.UserPerm.CanRemove = true
					view.UserPerm.CanUpdate = true
				}
			}
		}
		for _, userId := range viewItem.ExtraUpdateUserIdList {
			if userId == sessionItem.UserId {
				view.UserPerm.CanUpdate = true
			}
		}

		viewList = append(viewList, view)
	}

	return &project_dataview_api.ListViewResponse{
		Code:       project_dataview_api.ListViewResponse_CODE_OK,
		TotalCount: count,
		ViewList:   viewList,
	}, nil
}

func (apiImpl *ProjectDataViewApiImpl) GetView(ctx context.Context, req *project_dataview_api.GetViewRequest) (*project_dataview_api.GetViewResponse, error) {
	emptyInfo := &project_dataview_api.ViewInfo{
		UserPerm: &project_dataview_api.UserPerm{},
	}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_dataview_api.GetViewResponse{
			Code:   project_dataview_api.GetViewResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
			View:   emptyInfo,
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_dataview_api.GetViewResponse{
			Code:   project_dataview_api.GetViewResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
			View:   emptyInfo,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_dataview_api.GetViewResponse{
			Code:   project_dataview_api.GetViewResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
			View:   emptyInfo,
		}, nil
	} else if err != nil {
		return nil, err
	}
	viewItem, err := dataview_dao.ViewDao.Get(ctx, req.ProjectId, req.ViewId)
	if err != nil {
		return &project_dataview_api.GetViewResponse{
			Code:   project_dataview_api.GetViewResponse_CODE_NO_VIEW,
			ErrMsg: "数据视图不存在",
			View:   emptyInfo,
		}, nil
	}
	//获取用户信息
	userItemnList, err := user_dao.UserInfoDao.ListById(ctx, []string{viewItem.OwnerUserId})
	if err != nil {
		return nil, err
	}
	//生成结果
	view := viewItem.ToViewInfo()
	if len(userItemnList) > 0 {
		view.OwnerDisplayName = userItemnList[0].BasicInfo.DisplayName
		view.OwnerLogoUri = userItemnList[0].BasicInfo.LogoUri
	}
	view.ProjectName = projectItem.BasicInfo.ProjectName
	view.UserPerm = &project_dataview_api.UserPerm{}
	if viewItem.OwnerUserId == sessionItem.UserId || projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin {
		view.UserPerm.CanUpdate = true
		view.UserPerm.CanRemove = true
		view.UserPerm.CanUpdatePerm = true
	}

	for _, userId := range viewItem.ExtraUpdateUserIdList {
		if userId == sessionItem.UserId {
			view.UserPerm.CanUpdate = true
		}
	}

	return &project_dataview_api.GetViewResponse{
		Code: project_dataview_api.GetViewResponse_CODE_OK,
		View: view,
	}, nil
}

func (apiImpl *ProjectDataViewApiImpl) UpdateView(ctx context.Context, req *project_dataview_api.UpdateViewRequest) (*project_dataview_api.UpdateViewResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_dataview_api.UpdateViewResponse{
			Code:   project_dataview_api.UpdateViewResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_dataview_api.UpdateViewResponse{
			Code:   project_dataview_api.UpdateViewResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_dataview_api.UpdateViewResponse{
			Code:   project_dataview_api.UpdateViewResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_dataview_api.UpdateViewResponse{
			Code:   project_dataview_api.UpdateViewResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	viewItem, err := dataview_dao.ViewDao.Get(ctx, req.ProjectId, req.ViewId)
	if err != nil {
		return &project_dataview_api.UpdateViewResponse{
			Code:   project_dataview_api.UpdateViewResponse_CODE_NO_VIEW,
			ErrMsg: "数据视图不存在",
		}, nil
	}
	canUpdate := false
	for _, userId := range viewItem.ExtraUpdateUserIdList {
		if userId == sessionItem.UserId {
			canUpdate = true
		}
	}
	if !(canUpdate || viewItem.OwnerUserId == sessionItem.UserId || projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_dataview_api.UpdateViewResponse{
			Code:   project_dataview_api.UpdateViewResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = dataview_dao.ViewDao.Update(sessCtx, req.ProjectId, req.ViewId, req.Title, req.BgColor, req.Desc)
		if err != nil {
			return nil, err
		}
		return &project_dataview_api.UpdateViewResponse{
			Code: project_dataview_api.UpdateViewResponse_CODE_OK,
		}, nil
	})

	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_dataview.UpdateViewNotice{
		ProjectId: req.ProjectId,
		ViewId:    req.ViewId,
	})
	return ret.(*project_dataview_api.UpdateViewResponse), nil
}

func (apiImpl *ProjectDataViewApiImpl) RemoveView(ctx context.Context, req *project_dataview_api.RemoveViewRequest) (*project_dataview_api.RemoveViewResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_dataview_api.RemoveViewResponse{
			Code:   project_dataview_api.RemoveViewResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_dataview_api.RemoveViewResponse{
			Code:   project_dataview_api.RemoveViewResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_dataview_api.RemoveViewResponse{
			Code:   project_dataview_api.RemoveViewResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_dataview_api.RemoveViewResponse{
			Code:   project_dataview_api.RemoveViewResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	viewItem, err := dataview_dao.ViewDao.Get(ctx, req.ProjectId, req.ViewId)
	if err != nil { //对象不存在
		return &project_dataview_api.RemoveViewResponse{
			Code: project_dataview_api.RemoveViewResponse_CODE_OK,
		}, nil
	}
	if !(viewItem.OwnerUserId == sessionItem.UserId || projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_dataview_api.RemoveViewResponse{
			Code:   project_dataview_api.RemoveViewResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = dataview_dao.ViewDao.Remove(sessCtx, req.ProjectId, req.ViewId)
		if err != nil {
			return nil, err
		}
		err = dataview_dao.NodeDao.RemoveByView(sessCtx, req.ViewId)
		if err != nil {
			return nil, err
		}
		err = dataview_dao.EdgeDao.RemoveByView(sessCtx, req.ViewId)
		if err != nil {
			return nil, err
		}
		return &project_dataview_api.RemoveViewResponse{
			Code: project_dataview_api.RemoveViewResponse_CODE_OK,
		}, nil
	})

	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_dataview.RemoveViewNotice{
		ProjectId: req.ProjectId,
		ViewId:    req.ViewId,
	})
	return ret.(*project_dataview_api.RemoveViewResponse), nil
}

func (apiImpl *ProjectDataViewApiImpl) UpdateViewPerm(ctx context.Context, req *project_dataview_api.UpdateViewPermRequest) (*project_dataview_api.UpdateViewPermResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_dataview_api.UpdateViewPermResponse{
			Code:   project_dataview_api.UpdateViewPermResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_dataview_api.UpdateViewPermResponse{
			Code:   project_dataview_api.UpdateViewPermResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_dataview_api.UpdateViewPermResponse{
			Code:   project_dataview_api.UpdateViewPermResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_dataview_api.UpdateViewPermResponse{
			Code:   project_dataview_api.UpdateViewPermResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	viewItem, err := dataview_dao.ViewDao.Get(ctx, req.ProjectId, req.ViewId)
	if err != nil { //对象不存在
		return &project_dataview_api.UpdateViewPermResponse{
			Code: project_dataview_api.UpdateViewPermResponse_CODE_OK,
		}, nil
	}
	if !(viewItem.OwnerUserId == sessionItem.UserId || projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_dataview_api.UpdateViewPermResponse{
			Code:   project_dataview_api.UpdateViewPermResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	memberUserIdList, err := project_dao.MemberInfoDao.ListMemberId(ctx, req.ProjectId)
	if err != nil {
		return nil, err
	}
	memberUserIdMap := map[string]bool{}
	for _, memberUserId := range memberUserIdList {
		memberUserIdMap[memberUserId] = true
	}

	newUserIdList := []string{}
	for _, userId := range req.ExtraUpdateUserIdList {
		if memberUserIdMap[userId] {
			newUserIdList = append(newUserIdList, userId)
		}
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = dataview_dao.ViewDao.UpdateExtraUpdateUserIdList(sessCtx, req.ProjectId, req.ViewId, newUserIdList)
		if err != nil {
			return nil, err
		}
		return &project_dataview_api.UpdateViewPermResponse{
			Code: project_dataview_api.UpdateViewPermResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_dataview.UpdateViewNotice{
		ProjectId: req.ProjectId,
		ViewId:    req.ViewId,
	})
	return ret.(*project_dataview_api.UpdateViewPermResponse), nil
}
